package com.liaoyifan.core.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.InstantSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.liaoyifan.core.constant.Constants;
import com.liaoyifan.core.converter.handler.DateTimeHandler;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.TimeZone;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.web.multipart.MultipartFile;

@SuppressWarnings("unused")
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Log4j2
public class Json {

    public static final ObjectMapper OBJECT_MAPPER;
    public static final ObjectMapper SORT_MAPPER;

    static {
        OBJECT_MAPPER = builder().build();
        SORT_MAPPER =
                builder()
                        .enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)
                        .enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS)
                        .build();
    }

    /**
     * 将对象转换为 JSON 字符串
     *
     * @param obj 对象
     * @return JSON 字符串
     */
    public static String toString(Object obj) {
        if (obj == null) {
            return null;
        }
        return Try.run(() -> OBJECT_MAPPER.writeValueAsString(obj));
    }

    /** 从 JSON 字符串获取 JsonNode */
    public static JsonNode get(String str) {
        if (str == null || str.isBlank()) {
            return null;
        }
        return Try.run(() -> OBJECT_MAPPER.readTree(str));
    }

    /**
     * 将 JSON 字符串转换为对象
     *
     * @param str JSON 字符串
     * @param clazz 目标类型
     * @return 转换后的对象
     */
    public static <T> T parse(String str, Class<T> clazz) {
        if (str == null || str.isBlank()) {
            return null;
        }
        return Try.run(() -> OBJECT_MAPPER.readValue(str, clazz));
    }

    /**
     * 泛型支持的反序列化（如 List<T>, Map<String, T> 等）
     *
     * @param str JSON 字符串
     * @param typeReference 类型引用，例如：new TypeReference<List<User>>() {}
     * @return 泛型对象
     */
    public static <T> T parse(String str, TypeReference<T> typeReference) {
        if (str == null || str.isBlank()) {
            return null;
        }
        return Try.run(() -> OBJECT_MAPPER.readValue(str, typeReference));
    }

    /**
     * 泛型支持的反序列化 List<T>
     *
     * @param str JSON 字符串
     * @return 泛型集合
     */
    public static <T> List<T> parseArray(String str) {
        return parse(str, new TypeReference<>() {});
    }

    /** 对象转换 */
    public static <T> T convert(Object obj, Class<T> clazz) {
        if (obj == null) {
            return null;
        }
        return OBJECT_MAPPER.convertValue(obj, clazz);
    }

    /** 格式化输出 JSON */
    public static String toPretty(Object obj) {
        if (obj == null) {
            return null;
        }
        return Try.run(
                () -> OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(obj));
    }

    /** 排序输出 JSON */
    public static String sortJson(Object obj) {
        if (obj == null) {
            return null;
        }
        return Try.run(() -> SORT_MAPPER.writeValueAsString(obj));
    }

    private static JsonMapper.Builder builder() {
        return JsonMapper.builder()
                // 注册Java时间模块
                .addModule(createJavaTimeModule())
                // 注册自定义模块
                .addModule(createCustomModule())
                // 禁用危险特性，防止反序列化漏洞
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                .disable(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE)
                .disable(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY)
                // 启用宽松解析特性
                .enable(JsonReadFeature.ALLOW_TRAILING_COMMA.mappedFeature())
                // 序列化配置
                .serializationInclusion(JsonInclude.Include.NON_NULL)
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                // 性能优化
                .enable(JsonParser.Feature.USE_FAST_DOUBLE_PARSER)
                .enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)
                // 应用时区和日期格式
                .defaultTimeZone(TimeZone.getTimeZone(Constants.UTC_ZONE));
    }

    private static JavaTimeModule createJavaTimeModule() {
        // 创建日期格式化器
        DateTimeFormatter date = DateTimeHandler.getDateFormatter();
        DateTimeFormatter dateTime = DateTimeHandler.getDateTimeFormatter();
        // 创建JavaTimeModule并注册日期时间序列化/反序列化器
        JavaTimeModule module = new JavaTimeModule();
        module.addSerializer(LocalDate.class, new LocalDateSerializer(date));
        module.addDeserializer(LocalDate.class, new LocalDateDeserializer(date));
        module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(dateTime));
        module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(dateTime));
        return module;
    }

    private static SimpleModule createCustomModule() {
        SimpleModule module = new SimpleModule();
        module.addSerializer(Instant.class, InstantSerializer.INSTANCE);
        module.addDeserializer(Instant.class, InstantDeserializer.INSTANT);
        module.addSerializer(
                MultipartFile.class,
                new JsonSerializer<>() {
                    @Override
                    public void serialize(
                            MultipartFile multipartFile,
                            JsonGenerator jsonGenerator,
                            SerializerProvider serializerProvider)
                            throws IOException {
                        jsonGenerator.writeStartObject();
                        jsonGenerator.writeStringField("name", multipartFile.getOriginalFilename());
                        jsonGenerator.writeStringField(
                                "size", String.valueOf(multipartFile.getSize()));
                        jsonGenerator.writeStringField("type", multipartFile.getContentType());
                        jsonGenerator.writeEndObject();
                    }
                });
        module.addSerializer(
                HttpServletRequest.class,
                new JsonSerializer<>() {
                    @Override
                    public void serialize(
                            HttpServletRequest httpServletRequest,
                            JsonGenerator jsonGenerator,
                            SerializerProvider serializerProvider) {}
                });
        module.addSerializer(
                HttpServletResponse.class,
                new JsonSerializer<>() {
                    @Override
                    public void serialize(
                            HttpServletResponse httpServletResponse,
                            JsonGenerator jsonGenerator,
                            SerializerProvider serializerProvider) {}
                });
        return module;
    }
}
